#ifndef __SC_SYSTEM_H__
#define __SC_SYSTEM_H__

////////////////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////////////////

#include <string>
#include <vector>

#include "SC_LibConfig.h"

////////////////////////////////////////////////////////////////////////////////
// Namespaces
////////////////////////////////////////////////////////////////////////////////

namespace SC {

////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////

/**
 *  This class defines a "Systemic Computation" system.
 */
class LIBRARY_DECL SCSystem {

		friend class SCEngine;
		friend class SCData;

	public:
		
		/// Constructor
		SCSystem(const unsigned int = 0);
		
		/// Creates a copy of the given instance
		SCSystem(const SCSystem & inst);
		
		/// Affectation operator
		SCSystem & operator = (const SCSystem & inst);
		
		/// Grabs the given system
		const bool Grab(SCSystem &);
		
		/// Takes the ownership of the given system from the shared super-systems between the two systems interacting and the context
		const bool TakeFromSuperSystems(SCSystem &, const SCSystem &);
		
		/// Releases the given system
		const bool Release(SCSystem &);

		/// Releases the given system to the current system's parents
		const bool ReleaseToSuperSystems(SCSystem &);

		/// Returns the required substring from the first schema
		const std::string GetSchema1(const unsigned int = 0, const unsigned int = 0) const;
		
		/// Replaces the desired substring in the first schema
		void ReplaceSchema1(const std::string &, const unsigned int = 0, const unsigned int = 0);
		
		/// Returns the required substring from the kernel
		const std::string GetKernel(const unsigned int = 0, const unsigned int = 0) const;

		/// Replaces the desired substring in the kernel
		void ReplaceKernel(const std::string &, const unsigned int = 0, const unsigned int = 0);

		/// Returns the required substring from the second schema
		const std::string GetSchema2(const unsigned int = 0, const unsigned int = 0) const;
		
		/// Replaces the desired substring in the second schema
		void ReplaceSchema2(const std::string &, const unsigned int = 0, const unsigned int = 0);
		
		/// Returns the total definition
		const std::string GetDefinition() const { return this->schema1 + this->kernel + this->schema2; }

		/// Returns the number of super systems
		const unsigned int NbSuperSystems() const { return this->super_systems.size(); }
		
		/// Returns the ith super system (read-only)
		const SCSystem & GetSuperSystem(const unsigned int) const;
		
		/// Returns the number of sub systems
		const unsigned int NbSubSystems() const { return this->sub_systems.size(); }
		
		/// Returns the ith sub system (read-only)
		const SCSystem & GetSubSystem(const unsigned int) const;

		/// True if the given system is a super system of the current one
		const bool HasSuperSystem(const SCSystem &) const;

		/// True if the given system is a sub system of the current one
		const bool HasSubSystem(const SCSystem &) const;

		/// Returns the systems shared with the given one
		const std::vector<const SCSystem *> ShareWith(const SCSystem &) const;
		
		/// Returns true if the systems share another one
		const bool DoesShareWith(const SCSystem &) const;

	protected:
		
		/// Data [schema_1 function schema_2]
		std::string schema1, kernel, schema2;

		/// Scopes
		std::vector<SCSystem *> super_systems, sub_systems;

		/// Add the given system in the super system list
		void addSuperSystem(SCSystem &);

		/// Remove the given system from the super system list
		void removeSuperSystem(SCSystem &);

		/// Add the given system in the sub system list
		void addSubSystem(SCSystem &);

		/// Remove the given system from the sub system list
		void removeSubSystem(SCSystem &);

};

////////////////////////////////////////////////////////////////////////////////
// Closing Namespaces
////////////////////////////////////////////////////////////////////////////////

}

////////////////////////////////////////////////////////////////////////////////

#endif
